package com.katze.boot.file.servlet;

import com.katze.boot.file.entity.FileDatabaseEntity;
import com.katze.boot.file.entity.FileEntity;
import com.katze.boot.file.entity.FileTransfer;
import com.katze.boot.file.service.FileDatabaseService;
import com.katze.boot.file.service.FileService;
import com.katze.boot.file.service.FolderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.servlet.ServletRegistrationBean;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.concurrent.Semaphore;
import java.util.function.Consumer;

public class DefaultFileUploadService extends FileUploadService<FileDatabaseService>{
    private static final Logger log = LoggerFactory.getLogger(DefaultFileUploadService.class);

    @Resource
    private FileService fileService;

    @Resource
    private FolderService folderService;

    private Semaphore semaphore;

    private FileDatabaseEntity fileDatabase;

    @PostConstruct
    public void postConstruct() throws IOException {
        fileDatabase = fileSystemService.getCurrentFileDatabase();
        if (fileDatabase != null) {
            File dir = new File(fileDatabase.getPath(), fileDatabase.getCurrentFolderName());
            int count = (int) (fileDatabase.getMaxLimit() - dir.list().length);
            if (count <= 0) {
                folderService.create(fileDatabase, fileSystemService::updateCurrentFolderId);
                count = (int) fileDatabase.getMaxLimit();
            }
            semaphore = new Semaphore(count);
            log.info("{}目录剩余容量:{}", dir, count);
        } else {
            log.warn("文件仓尚未挂载文件库，请在挂载之后重启程序");
        }

    }

    public DefaultFileUploadService(ServletRegistrationBean<DefaultFileTransferServlet> servletRegistrationBean) {
        super(servletRegistrationBean);
    }

    @Override
    public File save(FileTransfer transfer, Consumer<File> save) throws Exception {
        FileDatabaseEntity fileDatabase = getFileDatabase();
        FileEntity entity = new FileEntity(transfer);
        entity.setFileDatabaseId(fileDatabase.getId());
        entity.setFileDatabaseExtendId(fileDatabase.getCurrentFolderId());
        entity.setPath(fileDatabase.getPath() + "/" + fileDatabase.getCurrentFolderName());
        return fileService.create(entity, save);
    }

    private FileDatabaseEntity getFileDatabase() throws Exception {
        boolean finish = false;
        int count = 0;
        try {
            semaphore.acquire();
            finish = semaphore.availablePermits() == 0;
            if (finish) {
                // 如果在使用过程中替换新目录则需要重新获取文件库信息，并计算出剩余数量
                FileDatabaseEntity nowFileDatabase = fileSystemService.getCurrentFileDatabase();
                if (!nowFileDatabase.getId().equals(fileDatabase.getId())) {
                    // 前后两个文件库不同则说明切换过文件库需要检验本地文件数量
                    File dir = new File(nowFileDatabase.getPath(), nowFileDatabase.getCurrentFolderName());
                    count = (int) (nowFileDatabase.getMaxLimit() - Files.list(dir.toPath()).count());
                }

                // 未超出限制时继续使用，反之需要重新创建新目录
                if (count <= 0)  {
                    // 当达到最大限制时会重新初始化文件库，但此时最后一个文件还没上传，故程序重启时上传文件后未达到最大限制就会切换目录
                    FileDatabaseEntity entity = (FileDatabaseEntity) fileDatabase.clone();
                    fileDatabase = nowFileDatabase;
                    log.info("当前{}/{}目录最大限制{}个文件,剩余容量{}需要重新创建存储目录", fileDatabase.getPath(), fileDatabase.getCurrentFolderName(), fileDatabase.getMaxLimit(), count);
                    folderService.create(fileDatabase, fileSystemService::updateCurrentFolderId);
                    count = (int) fileDatabase.getMaxLimit();
                    return entity;
                } else {
                    return fileDatabase = nowFileDatabase;
                }
            } else {
                return fileDatabase;
            }
        } finally {
            if (finish) {
                semaphore.release(count);
            }
        }
    }

//    //Semaphore 测试样例
//    public static void main(String[] args) {
//        Semaphore semaphore = new Semaphore(10);
//        Long[] l = new Long[]{new Date().getTime()};
//        for (int i = 0; i < 31; i++) {
//            new Thread(() -> {
//                boolean finish = false;
//                try {
//                    semaphore.acquire();
//                    finish = semaphore.availablePermits() == 0;
//                    System.out.println(l[0] + "成功进入停车场并停好车");
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                } finally {
//                    if (finish) {
//                        System.out.println("已清场");
//                        l[0] = new Date().getTime() + new Random().nextInt(2000);
//                        semaphore.release(15);
//                    }
//                }
//            }, i + "号车").start();
//        }
//    }
}
